<template>
  <div ref="containers" class="work-flows">
    <Toolbar
      :mousewheel-zoom="currentZoomScale"
      :history-btn-state="historyState"
      @zoom="handleZoom"
      @save="handleSave"
      @clear="handleClear"
      @history="handleHistory"
      @create="handleCreate"
    />
    <div class="work-flows__warp" style="width:100%; height:100%">
      <NodeBar
        @addNode="handleAddNode"
      />
      <div
        id="graph"
        ref="canvas"
        class="canvas"
      />

      <NodePropertyConfiguration
        ref="nodePropertyConfigurationRef"
        :config-form-type="configurationType"
        :base-config-form="baseConfiguration"
        :form-data="currentNodeData"
        :approval-type="approvalType"
        @cancel="handleConfigurationCancel"
        @save="handleConfigurationSave"
      />
    </div>

    <WithDialog
      :visible.sync="showConfirm"
      title="提示"
      confirm-text="恢复"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      width="10%"
      @confirm="handleRecover"
      @cancel="handleUnRecover"
    >
      <div style="font-size: 18px;">
        <i class="el-icon-info" /> 是否恢复上次保存的流程图？
      </div>
    </WithDialog>
  </div>
</template>
<script>
import { Graph } from '@antv/x6'
import { History } from '@antv/x6-plugin-history'
import { Dnd } from '@antv/x6-plugin-dnd'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Selection } from '@antv/x6-plugin-selection'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { graphLibs } from '@/views/approvalFlow/js/graphLib'
import Toolbar from '@/views/approvalFlow/components/workFlows/Toolbar.vue'
import NodeBar from '@/views/approvalFlow/components/workFlows/NodeBar.vue'
import workFlows from '@/mixins/workFlows'
import NodePropertyConfiguration from '@/views/approvalFlow/components/approvalTemplate/NodePropertyConfiguration.vue'
import { getApprovalType, createApprovalTemplates, getApprovalTemplatesDetails } from '@/api/approvalFlow'
import { sleep } from '@/utils'
import withDialog from '@/components/WithDialog/withDialog.vue'

export default {
  name: '',
  components: {
    WithDialog: withDialog,
    Toolbar,
    NodeBar,
    NodePropertyConfiguration
  },
  mixins: [workFlows],
  data() {
    return {
      graph: null,
      currentNode: null,
      dnd: null,
      stencil: null,
      showEditNodeDrawer: false,
      currentNodeData: null,
      currentEdge: null,

      // 右侧属性栏相关变量 ↓
      configurationType: 'base',
      configurationForm: null,
      baseConfiguration: {
        name: '',
        type_id: null
      },
      approvalType: null,
      showConfirm: false,
      approvalDetails: null
    }
  },
  computed: {
    getApprovalId() {
      console.log('this.$route.params --------->', this.$route.query)
      return this.$route.query.id
    }
  },
  created() {
  },
  mounted() {
    this.init()
    this.getApprovalType()

    if (this.getApprovalId) {
      this.getApprovalTemplatesDetails(this.getApprovalId)
    }
  },
  methods: {
    init() {
      const container = document.getElementById('graph')
      const width = container.offsetWidth
      this.graph = new Graph({
        container: container,
        width,
        autoResize: true,
        // height: 800,
        background: {
          color: '#fff'
        },
        snapline: false,
        ...graphLibs
      })

      this.registerEvent()

      // 节点拖拽创建
      this.dnd = new Dnd({
        target: this.graph,
        scaled: false
      })

      // 启用撤销/恢复 动作插件
      this.graph.use(
        new History({
          enabled: true,
          stackSize: 20,
          beforeAddCommand: (a, args) => {
            // 忽略节点和边tool的历史变更
            if (
              args.key === 'tools' ||
              args.key === 'zIndex' ||
              (args.key === 'attrs' && args.cell?.shape === 'edge')
            ) {
              return false
            }

            if (args.key === undefined && this.graph.isEdge(args.cell)) {
              args.cell.removeTools()
            }
          }
        })
      )

      // 对齐线
      this.graph.use(
        new Snapline({
          enabled: true,
          clean: false,
          className: 'custom-snap-line'
        })
      )

      // 框选
      this.graph.use(
        new Selection({
          enabled: true,
          multiple: true,
          rubberband: true,
          movable: true,
          showNodeSelectionBox: true
        })
      )

      this.graph.use(
        new Keyboard({
          enabled: true
          // global: true
        })
      )

      this.graph.centerContent()

      // 添加事件监听
      this.addNodeEvent()

      this.getLocalGraph()
    },

    async getApprovalType() {
      try {
        const res = await getApprovalType()
        this.approvalType = res.data
      } catch (error) {
        this.$message.error('审批类型获取失败')
      }
    },

    handleAddNode({ node, e }) {
      const activity = {
        type: 'countersign',
        name: '审批人',
        assignees: [{ assignee_type: 'user', assignee_id: null, assignee_name: '' }]
      }

      const nodeDataMap = {
        'start-event': { name: '开始' },
        'end-event': { name: '结束' },
        'activity': activity,
        'exclusive-gateway': { name: '条件分支' }
        // 'parallel-gateway': { name: '并行网关' }
      }
      const createNode = this.graph.createNode({
        id: `${node.shape}_${new Date().getTime()}`,
        shape: node.shape,
        zIndex: 10,
        data: nodeDataMap[node.shape]
      })

      this.dnd.start(createNode, e)
    },

    handleZoom(factor) {
      this.graph.zoomTo(factor)
      // this.graph.zoom(factor, { minScale: 0.5, maxScale: 3 })
    },

    handleDragOver(event) {
      event.preventDefault()
      event.dataTransfer.dropEffect = 'move'
    },

    handleDrop(event) {
      event.preventDefault()
    },

    handleSave() {
      this.nodeToolsRemove()
      this.edgesRemove()
      const graphAllInfo = this.graph.toJSON()
      // const nodeInfo = this.graph.getNodes()

      window.localStorage.setItem('graphAllInfo', JSON.stringify({ graphInfo: graphAllInfo, templateInfo: this.baseConfiguration }))
    },

    handleClear() {
      this.graph.clearCells()
    },

    handleHistory(type) {
      this.graph[type]()
    },

    handleClose() {
      if (this.currentNode) {
        this.currentNode.setData({
          ...this.currentNodeData
        })

        if (this.currentNode.shape === 'activity') {
          this.currentNode.setAttrs({ label: { text: this.currentNodeData.name }})
        }
      } else if (this.currentEdge) {
        this.currentEdge.setData({
          ...this.currentNodeData
        })
        const data = this.currentEdge.getData()
        this.currentEdge.setLabels(this.currentNodeData.name)
      }

      this.currentNodeData = null
    },

    handleConfigurationCancel() {
      this.configurationType = 'base'
      if (this.currentNode) {
        this.currentNode.removeTools()
        this.currentNode = null
      }

      if (this.currentEdge) {
        this.currentEdge.removeTools()
        this.currentEdge = null
      }

      this.currentNodeData = null
    },

    handleConfigurationSave(e) {
      console.log('e --------->', e)
      if (this.currentNode) {
        if (this.currentNode.shape === 'activity') {
          // this.currentNode.setAttrs({ label: { text: labelText }})
          const data = {
            name: e.name,
            type: e.type,
            assignees: e.assignees
          }
          this.currentNode.setData(data, { overwrite: true })
        } else {
          this.currentEdge.setData(e, { overwrite: true })
        }

        this.currentNode.removeTools()
      } else if (this.currentEdge) {
        this.currentEdge.setData(e, { overwrite: true })
        this.currentEdge.setLabels(e.name)

        this.currentEdge.removeTools()
      }
      this.currentNode = null
      this.currentEdge = null
      this.currentNodeData = null
      this.configurationType = 'base'
    },
    async handleCreate() {
      const data = {
        ...this.baseConfiguration,
        content: JSON.stringify(this.graph.toJSON().cells),
        nodes: this.nodesFormat(this.graph.toJSON().cells)
      }

      const error = await this.handleValidate(data)
      if (error > 0) return
      data.nodes = JSON.stringify(data.nodes)
      try {
        const res = await createApprovalTemplates(data)
        this.$message.success(this.$route.query.id ? '修改成功' : '创建成功')
        this.clearLocalData()
        this.$router.back()
      } catch (error) {
        const editErr = this.$route.query.id && error?.response?.data?.message ? error?.response?.data?.message : '修改失败'
        const createErr = !this.$route.query.id && error?.response?.data?.message ? error?.response?.data?.message : '创建失败'

        this.$message.error(this.$route.query.id ? editErr : createErr)
      }
    },

    nodesFormat(nodes) {
      const result = []
      for (const node of nodes) {
        if (node.shape === 'activity') {
          result.push(node.data)
        }
      }

      return result
    },

    async handleValidate(data) {
      let error = 0
      if (this.configurationType === 'base') {
        const res = await this.$refs.nodePropertyConfigurationRef.templateConfigFormValidate()
        if (!res) error += 1
      } else {
        if (!data.name || !data.type_id) {
          this.$notify.error({
            title: '错误',
            message: '请将模板信息补充完整！'
          })
          this.configurationType = 'base'
          error += 1
        }
      }
      await sleep(300)
      for (const node of data.nodes) {
        if (node.shape === 'activity') {
          for (const assignee of node.data.assignees) {
            if (!assignee.assignee_id) {
              this.$notify.error({
                title: '错误',
                message: '请将审批人信息补充完整！'
              })
              error += 1
              break
            }
          }
          break
        }
      }

      return error
    },

    clearLocalData() {
      window.localStorage.removeItem('graphAllInfo')
    },

    getLocalGraph() {
      const graphInfo = window.localStorage.getItem('graphAllInfo')
      if (graphInfo) {
        this.showConfirm = true
      }
    },

    handleRecover() {
      const graphInfo = window.localStorage.getItem('graphAllInfo')
      const data = JSON.parse(graphInfo)
      this.graph.fromJSON(data.graphInfo.cells)
      this.baseConfiguration = data.templateInfo
      this.graph.cleanHistory()
      this.showConfirm = false
    },

    handleUnRecover() {
      this.clearLocalData()
      this.showConfirm = false
    },

    async getApprovalTemplatesDetails(id) {
      try {
        const res = await getApprovalTemplatesDetails({ id })
        this.approvalDetails = res.data
        this.baseConfiguration = {
          name: res.data.name,
          type_id: res.data.event_type / 1
        }
        this.graph.fromJSON(JSON.parse(res.data.content))
        this.graph.cleanHistory()
      } catch (error) {
        this.$message.error(error?.response?.data?.message || '获取模板失败')
      }
    },
    test() {
      this.graph.centerContent()
    }
  }
}
</script>
<style lang="scss" scoped>
.work-flows {
  position: relative;
  //height: calc(100vh - 84px);
  &__warp {
    position: relative;
    display: flex;
    width: 100%;
    height: calc(100vh - 84px - 40px);

    #stencil {
      width: 170px;
      background-color: #fff;
    }

    #graph {
      flex: 1;
      box-sizing: border-box;
    }
  }

  ::v-deep(.x6-widget-selection-box) {
    //border: 2px dashed #239edd;
    //display: none;
    border: none;
    box-shadow: none;
  }

  ::v-deep(.x6-widget-selection-inner) {
    border: 1px solid #239edd;
    //border: none;
  }

  ::v-deep(.x6-widget-snapline-horizontal) {
    stroke: #409EFF;
  }

  ::v-deep(.x6-widget-snapline-vertical) {
    stroke: #409EFF;
  }
}

.node-edit {
  padding: 20px;
}

</style>
